import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { DECORATOR, EXCEPTION } from 'src/constants';
import { RuntimeException } from 'src/exceptions/runtime.exception';
import { Role } from 'src/role/role.model';
import { Permission } from './permission.model';
import { Op } from 'sequelize';
import { UserService } from 'src/user/user.service';
import { RoleService } from 'src/role/role.service';

@Injectable()
export class PermissionsGuard implements CanActivate {
  constructor(
    private reflector: Reflector,
    private userService: UserService,
    private roleService: RoleService,
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 如果没有登录过，不需要检查权限了
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    if (!user) {
      return true;
    }
    console.log('common-api/src/permission/permission.guard.ts:25', user);
    if (user?.root) {
      return true;
    }
    const userModel = await this.userService.findOneWith(
      { id: user.sub },
      Role,
    );
    console.log(
      'roles',
      userModel.roles.map((role) => role.code),
    );
    const roles = await this.roleService.findAllWith(
      {
        id: { [Op.in]: userModel.roles.map((role) => role.id) },
      },
      Permission,
    );
    // console.log(JSON.stringify(roles, null, 2));
    const permissions = roles
      .map((role) => role.permissions.map((permission) => permission.code))
      .flat();
    console.log('permissions', permissions);

    const requiredPermissions = this.reflector.getAllAndOverride<string[]>(
      DECORATOR.PERMISSIONS_KEY,
      [context.getHandler(), context.getClass()],
    );
    // requiredPermissions = undefined 表示装饰器 @Permissions() 压根不存在
    if (!requiredPermissions) {
      throw new RuntimeException('PERMISSION ERROR', EXCEPTION.NO_PERMISSION);
    }
    const isPermission = requiredPermissions.some((permission) =>
      permissions.includes(permission),
    );
    if (!isPermission) {
      throw new RuntimeException('NOT PERMISSION', EXCEPTION.NO_PERMISSION);
    }
    // 扩展角色 roles 和权限 permissions 到 user 属性中
    request.user['roles'] = roles;
    request.user['permissions'] = permissions;
    return true;
  }
}
